<template>
  <div>
    <div :class="streaming ? 'typedText' : 'typedText-done'" ref="text">
      <div v-html="parsedMarkdown"></div>
    </div>
  </div>
</template>

<script>
import { marked } from "marked";

export default {
  name: "TypedText",
  props: {
    typedList: {
      type: String,
      default: "",
    },
    streaming: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      displayedText: "",
      renderIndex: 0,
      renderTimer: null,
      lastScrollTime: 0, // 用于手动实现节流
    };
  },
  computed: {
    parsedMarkdown() {
      return marked(this.displayedText);
    },
  },
  watch: {
    typedList: {
      handler(newVal, oldVal) {
        this.clearTimer();
        this.renderChunkedText(newVal);
      },
      immediate: true,
    },
    streaming(newVal) {
      if (!newVal) {
        this.clearTimer();
        this.displayedText = this.typedList;
        this.scrollToBottom();
      }
    },
  },
  beforeUnmount() {
    this.clearTimer();
  },
  methods: {
    clearTimer() {
      if (this.renderTimer) {
        clearTimeout(this.renderTimer);
        this.renderTimer = null;
      }
      this.renderIndex = 0;
    },

    renderChunkedText(newText) {
      const startIndex = this.displayedText.length;
      const newContent = newText.slice(startIndex);

      // 分批处理字符
      const chunkSize = this.calculateChunkSize(newContent);
      let currentIndex = 0;

      const renderNextChunk = () => {
        const end = currentIndex + chunkSize;
        const chunk = newContent.slice(currentIndex, end);
        this.displayedText += chunk;
        currentIndex = end;

        this.scrollToBottom();

        if (currentIndex < newContent.length) {
          this.renderTimer = setTimeout(
            renderNextChunk,
            this.getRenderDelay(chunk)
          );
        }
      };

      renderNextChunk();
    },

    calculateChunkSize(content) {
      // 根据内容类型动态调整块大小
      if (content.startsWith("```") || content.startsWith("    ")) {
        return 20; // 代码块加大块大小
      }
      return content.includes(" ") ? 5 : 1;
    },

    getRenderDelay(chunk) {
      // 根据字符类型调整渲染速度
      if (chunk.match(/[\n\r]/)) return 0;
      if (chunk.match(/[^a-zA-Z0-9]/)) return 30;
      return Math.random() * 20 + 20;
    },

    scrollToBottom() {
      // 手动实现节流功能
      const now = Date.now();
      if (now - this.lastScrollTime < 10) return; // 100ms 节流间隔
      this.lastScrollTime = now;

      this.$nextTick(() => {
        const container = document.getElementsByClassName("chat-body-info")[0];
        if (container) {
          const isNearBottom =
            container.scrollTop + container.clientHeight + 50 >=
            container.scrollHeight;
          if (isNearBottom) {
            container.scrollTop = container.scrollHeight;
          }
        }
      });
    },
  },
};
</script>

<style scoped>
/* 保持原有样式不变 */
.typedText::after {
  content: "|";
  animation: blink 1s infinite;
}

.typedText-done::after {
  content: "";
  opacity: 1;
}

@keyframes blink {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* 优化 Markdown 渲染过渡 */
:deep(pre) {
  transition: opacity 0.3s ease;
}

/* 添加打字机效果音频（可选） */
.typedText {
  position: relative;
}

.typedText::before {
  content: "";
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    to bottom,
    transparent 95%,
    rgba(0, 0, 0, 0.1) 95%
  );
  background-size: 100% 1.2em;
}
</style>
